iT邦幫忙

0

用閉包實作datePicker封裝

  • 分享至 

  • xImage
  •  
  • 前言
    由於我在一開始很傻的自己刻了日曆,想說版面看起來很簡單,但沒有考慮到動態互動選擇日期的功能,自以為這麼簡單,自己刻一刻就好,頭都洗一半了,只好繼續完成,花了一些時間把start date動態互動完成後,由於end date要做的事一模一樣,不可能重新寫一次,這樣太傻了,我想一定可以共用程式碼的吧!於是找啊找,恩...原來這叫封裝,而且就是套件的原理來著,還好自己似乎沒有太笨XD竊喜一下,但...知道要做什麼卻不見得做得出來,東試試西trytry,已經封到不知道哪去了,可能自己會先瘋掉,瞥眼一見,饅頭先生到了,用渴望的眼神向他求救,他竟然用閉包解決了我本來卡在constructor繞不出來的窘境,原來這麼簡單啊!好想跟他的腦交換一下XD

  • 先介紹datePicker功能

    • 起始畫面,預設日期為當日https://ithelp.ithome.com.tw/upload/images/20240326/20163234tLaw1BPSJe.png
    • calender: 點擊日期欄位會跳出Calendar,當日會反底色,其他日期hover後會反底色,標題欄位之左右方箭頭可切換月份,標題"March 2024"按下後會跳出另一個可單獨選擇月份的monthPanel
      https://ithelp.ithome.com.tw/upload/images/20240326/201632342FGRnixzSt.png
    • monthPanel:動態互動效果與calendar類似,中間標題"2024"按下後會跳出另一個可單獨選擇年份的yearPanel
      https://ithelp.ithome.com.tw/upload/images/20240326/20163234iEXFbVciPA.png
    • yearPanel:同理
      https://ithelp.ithome.com.tw/upload/images/20240326/20163234GCWZqNYGKF.png
    • 使用者點擊自己欲指定年份,會跳回monthPanel,指定月份後跳回calendar,指定日期後,calendar消失,選取完起始畫面的日期必須跟著變動
  • 實作步驟

    • 首先把html跟javascript的程式碼並排對照
    • 整理程式碼,單純函式不影響,其他程式碼就要考慮放的位置是否合適,例如:原本calendar,monthPanel跟yearPanel裡與起始畫面日期連動的程式碼如下,我寫在init()之外,其實照理說應該在包在init()中。菜菜如我傻傻不自知,饅頭先生就幫我把它整理進去
            let dayElement = document.querySelector(`${targetSelector} #dayElement`);
            dayElement.addEventListener("click", function(event) {
                if (event.target.className.includes("visible_date")) {
                    datePicked.setDate(event.target.textContent);
                    datePicked.setMonth(state.current.getMonth());
                    datePicked.setYear(state.current.getFullYear());
                    showDatePicked(datePicked, datePicker);
                    render();
                }
            });
    
            let monthElement = document.querySelector(`${targetSelector} #monthElement`);
            monthElement.addEventListener("click", function(event) {
                if (event.target.className.includes("visible_month")) {
                    let monthOrder = monthAbbreviation.indexOf(event.target.textContent);
                    datePicked.setMonth(monthOrder);
                    datePicked.setYear(state.current.getFullYear());
                    showDatePicked(datePicked, datePicker);
                    monthChange(monthOrder);
                    render();
                }
            });
    
            let yearElement = document.querySelector(`${targetSelector} #yearElement`);
            yearElement.addEventListener("click", function(event) {
                if (event.target.className.includes("visible_year")) {
                    datePicked.setYear(event.target.textContent);
                    showDatePicked(datePicked, datePicker);
                    yearChange(event.target.textContent);
                    render();
                }
            });
    
    • 確認封裝範圍,剪下HTML程式碼
    • 創造函式renderHTML(element)
    • 剛才剪下的整串程式碼即為renderHTML函式內容
            function renderHTML(element){
                element.innerHTML = `...剛剛剪下的程式碼`
            }
    
    • 再來加上下面程式碼:
            const datePickerWrapper = document.querySelector('#datePickerFrom');
            renderHTML(datePickerWrapper);
    
    • 由於datePickerFrom是給start date用的,所以要改成變數,之後才可以再創一個datePickerTo給end date用,於是閉包就登場啦!登登登登登
            function componentDatePicker(targetSelector) {
                function renderHTML (element) {
                element.innerHTML = `......`
                }
                const datePickerWrapper = document.querySelector(targetSelector);
                renderHTML(datePickerWrapper);
            }
    
    • 再來就是呼叫
            componentDatePicker("#datePickerFrom");
            componentDatePicker("#datePickerTo");
    
    • 基本上靜態的html到此就已經ok了,之後再原封不動的把已完成的javascript程式碼也搬到componentDatePicker內容接續在底下,該跟著加上targetSelector的地方記得加上就大功告成囉!
      • 舉例:原本只有寫#previousMonth,前面要加上${targetSelector}才能找到在targetSelector底下的dom element
          const previousMonth = document.querySelector(`${targetSelector} #previousMonth`)
          previousMonth.addEventListener('click', function() {
          state.current.setMonth(state.current.getMonth() - 1);
          render();
          })
      
  • 大致實作步驟就介紹到這裡,講個概念,也許有需要的人應該能有一點靈感,整包太繁雜就不放了。封裝完成後,成就感滿滿ㄚ!太感動了

  • 參考資料

    • 可敬的饅頭先生腦XD

圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言